/*
 * NInputGateDescription.java
 * 
 * last update: 16.01.2010 by Stefan Saru
 * 
 * author:	Alec(panovici@elcom.pub.ro)
 * 
 * Obs:
 */

package engine;

import java.util.*;
import java.io.*;
import middle.*;

/**
 * n_input_gate can be one of the following:
 * and/nand/or/nor/xor/xnor
 */

class NInputGateDescription extends StdGateDescription
{
	NInputGateDescription (byte type) {
		super(type, 2);
	}

	///////////////////////////////
	// ModuleFactory implementation
	///////////////////////////////


	public Object createNewModule(NameSpace parent,
			ModuleInstanceDescription miDesc,
			byte strength,
			ScopeNode scope)
	throws ParseException
	{
		xConsole.debug("creating new NInputGate");
		SelectionExpressionDescription inputs =
			new SelectionExpressionDescription();
		ExpressionDescription output;
		Enumeration e = miDesc.portsVector.elements();
		output = (ExpressionDescription) e.nextElement();
		if (output == null) {
			xConsole.debug("NInputGate not created: output is null");
			return null; //no output, so ..
		}
		try {
			((AssignableSelection)output).toContSelection(strength);
		} catch (ClassCastException cex) {
			throw new ParseException (parent.desc.toString(miDesc.lineNo) +
					": error: output expression is not" +
			" a net selection or concatenation");
		}

		//unconnected ports are assumed to be '1bZ'
		while(e.hasMoreElements()) {
			ExpressionDescription ck = (ExpressionDescription)e.nextElement();
			inputs.addChunk(ck != null? ck : ConstantDescription.zDescription);
		}

		return new NInputGate (parent, delay,
				(LeftValue) output.instantiate(parent),
				inputs.instantiate(parent), miDesc, type);
	}

	public Object createNewModuleArray(NameSpace parent,
			ModuleInstanceDescription miDesc,
			byte strength,
			ScopeNode scope, int ars, int are,
			int n, int increment)
	throws ParseException
	{
		Enumeration en = miDesc.portsVector.elements();
		ExpressionDescription output = (ExpressionDescription) en.nextElement();
		if (output == null) return null; //no output, so ..

		NInputGate gates[] = new NInputGate[n];
		Vector[] inputs  = new Vector[n]; //the input chunks
		for (int i = 0; i < n; i++)
			inputs[i] = new Vector();
		LeftValue[] outputs = new LeftValue[n];
		Monitor m;

		try {
			((AssignableSelection) output).toContSelection(strength);
		} catch (ClassCastException cex) {
			throw new ParseException(parent.desc.toString(miDesc.lineNo) +
					": error: bad output port expression: not a net");
		}

		LeftValue out;
		try {
			out = (LeftValue) output.instantiate(parent);
		} catch (ClassCastException cex) {
			throw new ParseException (parent.desc.toString(miDesc.lineNo) +
					": error: bad output port expression: not a lValue");
		}

		if (((Expression) out).length != 1) {
			if (((Expression) out).length != n)
				throw new ParseException (parent.desc.toString(miDesc.lineNo) +
						": error: bad output port length");


			BitVector buffer = new BitVector (out.length() -1, 0, false);
			for (int i = n-1; i >= 0 ; i--)
				outputs[i] = new BitSelect(parent, buffer, null, i, i);

			m = new LinkMonitor(out, new BitSelect(parent, buffer, null, n-1, 0));
		} else {
			outputs[0] = out;
			for (int i = 1; i < n; i++)
				outputs[i] = (LeftValue) output.instantiate(parent);
		}

		while (en.hasMoreElements()) { //the inputs
			ExpressionDescription ed =
				(ExpressionDescription) en.nextElement();
			Expression e =
				ed == null ? ConstantDescription.zDescription.instantiate(parent) :
					ed.instantiate(parent);

				if (e.length != 1) {
					if (e.length != n)
						throw new ParseException(parent.desc.toString(miDesc.lineNo) +
								": error: bad input port expression length for \"" +
								ed + "\"");
					BitVector buffer = new BitVector(e.length - 1, 0, false);
					m = new LinkMonitor(new BitSelect(parent, buffer,
							null, n-1, 0),
							e);
					for (int i = n-1; i >= 0; i--)
						inputs[i].addElement(new BitSelect(parent, buffer, null, i, i));
				} else
					for (int i = 0; i < n; i++)
						inputs[i].addElement(e);
		}

		for (int i = 0; i < n; i++) {
			gates[i] = new NInputGate(parent, delay, outputs[i],
					new SelectionExpression (parent,
							inputs[i],
							-8778),
							miDesc, type);
		}

		return gates;
	}

}







